package com.touchapk.core;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.touchapk.engine.ADBRemoteFile;
import com.touchapk.engine.ADBScreenshotType;
import com.touchapk.engine.ADBShellCommands;
import com.touchapk.opencv.Finder;
import com.touchapk.service.ADBService;
import com.touchapk.service.impl.ADBServiceImpl;

/**
 * @description
 * @author yangkeyun
 * @email coyun@qq.com
 * @date 2016年7月6日
 * @version V1.0
 */
public class Events {

	public static ADBService adbService = new ADBServiceImpl();

	public static Map<String,String> activeUdids=new HashMap<String,String>();
	
	private static Finder finder = new Finder();

	private String deviceUdid;// 设备id

	private String event;

	/**
	 * @return the deviceUdid
	 */
	public String getDeviceUdid() {
		return deviceUdid;
	}
	

	/**
	 * 
	 * @author yangkeyun
	 * @description
	 *            is Udid index
	 * @return
	 */
	public int initDeviceByUdid(String udid) {

		if(!activeUdids.containsKey(udid)){return 2;}
		
		this.deviceUdid=udid;
		
		this.getEvent();
			
		if ("".equals(this.event)){return 3;}
		
		return 1;
	}

	
	
	public void getEvent() {
		try {
			String str = adbService.executeShellCommand(this.deviceUdid,
					ADBShellCommands.GET_EVENT);
			Pattern p = Pattern.compile("(?<=add device 1:)(.*)(?=\\s)");
			Matcher m = p.matcher(str);
			if (m.find()) {
				this.event = m.group(1);
			}
		} catch (Exception e) {}
		
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 停止指定毫秒
	 * @param ms
	 * @return
	 */
	public boolean mSleep(int ms) {
		try {
			adbService.executeShellCommand(this.deviceUdid, String.format("usleep %s", ms * 1000));
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description get the screen width and height
	 * @return an array 0=w,1=h
	 */
	public int[] getScreenSize() {
		int s[] = { -1, -1 };
		try {
			String str = adbService.executeShellCommand(this.deviceUdid,
					ADBShellCommands.GET_DISPLAY_INFORMATION_WINDOW);
			Pattern p = Pattern
					.compile("(?<=init=)(\\d{3,4})x(\\d{3,4})(?=\\s)");
			Matcher m = p.matcher(str);
			if (m.find()) {
				s[0] = Integer.valueOf(m.group(1));
				s[1] = Integer.valueOf(m.group(2));
			}
		} catch (Exception e) {
		}

		return s;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean touchDown(int x, int y) {
		StringBuffer script = new StringBuffer(512);
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.BTN_TOUCH, 1));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_PRESSURE, 1));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_X, x));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_Y, y));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_MT_REPORT, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");

		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {

		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean touchUp(int x, int y) {
		StringBuffer script = new StringBuffer(512);
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.BTN_TOUCH, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_PRESSURE, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_X, x));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_Y, y));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_MT_REPORT, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");

		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {

		}

		return false;
	}

	public boolean touchMove(int x, int y) {
		StringBuffer script = new StringBuffer(512);

		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_X, x));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_ABS, InputEvent.ABS_MT_POSITION_Y, y));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_MT_REPORT, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");

		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {

		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 触摸返回键
	 * @return
	 */
	public boolean touchBack() {
		StringBuffer script = new StringBuffer(512);

		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.KEY_BACK, 1));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.KEY_BACK, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");
		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 触摸home键
	 * @return
	 */
	public boolean touchHome() {
		StringBuffer script = new StringBuffer(512);
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.KEY_HOME, 1));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_KEY, InputEvent.KEY_HOME, 0));
		script.append("\n");
		script.append(String.format("sendevent %s %s %s %s", this.event,
				InputEvent.EV_SYN, InputEvent.SYN_REPORT, 0));
		script.append("\n");
		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 打开指定url
	 * @param url
	 * @return
	 */
	public boolean openUrl(String url) {

		try {
			adbService.executeShellCommand(this.deviceUdid,
					"am start -a android.intent.action.VIEW -d " + url);
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 获取默认输入法
	 * @return
	 */
	public String getInPutMethod() {
		try {
			return adbService.executeShellCommand(this.deviceUdid,
					"settings get secure default_input_method");
		} catch (Exception e) {
		}
		return "";
	}

	public boolean setInPutMethod(String method) {

		StringBuffer script = new StringBuffer(512);
		script.append(String.format("ime enable  %s", method));
		script.append("\n");
		script.append(String.format(
				"settings put secure default_input_method %s", method));
		script.append("\n");
		try {
			adbService.executeShellCommand(this.deviceUdid, script.toString());
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 安装应用
	 * @param path
	 * @return
	 */
	public boolean install(String path) {

		try {
			long time = System.currentTimeMillis();

			String apk = "i" + time + ".apk";
			adbService.pushFile(this.deviceUdid, new File(path),
					new ADBRemoteFile("/data/local/tmp/" + apk));

			StringBuffer script = new StringBuffer(512);
			script.append(String
					.format("pm install -f /data/local/tmp/%s", apk));
			script.append("\n");
			script.append(String.format("rm /data/local/tmp/%s", apk));
			script.append("\n");

			String r = adbService.executeShellCommand(this.deviceUdid,
					script.toString());
			if (r.indexOf("Success") != -1)
				return true;
			return false;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 卸载apk
	 * @param path
	 * @return
	 */
	public boolean unInstall(String path) {

		StringBuffer script = new StringBuffer(512);
		script.append(String.format("pm uninstall  %s", path));
		script.append("\n");

		try {
			String r = adbService.executeShellCommand(this.deviceUdid,
					script.toString());
			if ("Failure".equals(r))
				return false;
			return true;
		} catch (Exception e) {
		}

		return false;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 获取已安装的应用
	 * @return
	 */
	public Object[] getInstalledApps() {
		List<String> appList = new ArrayList<String>();

		try {
			String reslut = adbService.executeShellCommand(this.deviceUdid,
					"pm list packages");
			Pattern p = Pattern.compile("(?<=package:)(.*)(?=\\s)");
			Matcher m = p.matcher(reslut);

			while (m.find()) {
				appList.add(m.group());
			}
		} catch (Exception e) {
		}

		return appList.toArray();
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 获取应用的安装路径
	 * @param path
	 * @return
	 */
	public String appBundlePath(String path) {
		String apk = "";
		try {
			String reslut = adbService.executeShellCommand(this.deviceUdid,
					"pm path " + path);
			Pattern p = Pattern.compile("(?<=package:)(.*)(?=\\s)");
			Matcher m = p.matcher(reslut);
			if (m.find()) {
				apk = m.group();
			}
		} catch (Exception e) {
		}

		return apk;
	}

	public Object[] getAppVersionInfo(String path) {
		List<String> appList = new ArrayList<String>();

		try {
			String reslut = adbService.executeShellCommand(this.deviceUdid,
					"dumpsys package " + path);
			Pattern p = Pattern
					.compile("(?<=versionCode=)(\\d+)(?=\\s)|(?<=versionName=)(.*)(?=\\s)");
			Matcher m = p.matcher(reslut);
			while (m.find()) {
				appList.add(m.group());
			}
		} catch (Exception e) {
		}

		return appList.toArray();
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 启动应用句柄
	 * @param path
	 * @return
	 */
	public String getAppStartHandle(String path) {
		String apk = "";
		try {
			String reslut = adbService.executeShellCommand(this.deviceUdid,
					"dumpsys package " + path);
			Pattern p = Pattern
					.compile("(?<=android\\.intent\\.action\\.MAIN:)([.|\\n|\\s|\\S]*)(?=Category: \"android\\.intent\\.category.LAUNCHER\")");
			Matcher m = p.matcher(reslut);
			if (m.find()) {
				String str = m.group();
				p = Pattern.compile("(?<=" + path + ")(.*)(?= filter)");
				m = p.matcher(str);
				while (m.find()) {
					apk = path + m.group();
				}
			}
		} catch (Exception e) {
		}

		return apk;
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 文明获取坐标
	 * @param texts
	 * @param fontHeight
	 * @param degree
	 * @return
	 */
	public int[] findText(String[] texts, Integer fontHeight, int degree) {
		if (fontHeight == null || fontHeight == 0) {
			fontHeight = 30;
		}

		double de = 1 + degree / 100.00;

		try {
			byte[] data = adbService.getScreenshot(this.deviceUdid,
					ADBScreenshotType.PNG);
			return finder.findText(data, texts, fontHeight, de);
		} catch (Exception e) {
			e.printStackTrace();
			return new int[] { -1, -1 };
		}
	}

	/**
	 * 
	 * @author yangkeyun
	 * @description 指定坐标获取颜色值
	 * @param x
	 * @param y
	 * @return
	 */
	public int[] getColor(int x, int y) {
		try {
			byte[] data = adbService.getScreenshot(this.deviceUdid,
					ADBScreenshotType.PNG);
			return finder.getColor(data, x, y);
		} catch (Exception e) {
			return new int[] { -1, -1 };
		}
	}

	public int[][] findColor(String bgr, double degreeStart, double degreeEnd) {

		try {
			byte[] data = adbService.getScreenshot(this.deviceUdid,
					ADBScreenshotType.PNG);
			List<int[]> result = finder.findColor(data, bgr, degreeStart,
					degreeEnd);
			int[][] r = new int[result.size()][2];
			for (int i = 0; i < result.size(); i++) {
				r[i][0] = result.get(i)[0];
				r[i][1] = result.get(i)[1];
			}
			return r;
		} catch (Exception e) {
			return new int[][] { new int[] {} };
		}

	}

	public int[][] findColorRefer(String bgr, String subColorBGR,
			int direction, String subColorBGR1, int direction1,
			double degreeStart, double degreeEnd) {

		try {

			byte[] data = adbService.getScreenshot(this.deviceUdid,
					ADBScreenshotType.PNG);

			List<int[]> result = null;

			if ((subColorBGR != null && !"".equals(subColorBGR))
					&& (subColorBGR1 == null || "".equals(subColorBGR1))) {
				result = finder.findColor(data, bgr, degreeStart, degreeEnd,
						subColorBGR, direction);

			} else if ((subColorBGR != null && !"".equals(subColorBGR))
					&& (subColorBGR1 != null && !"".equals(subColorBGR1))) {
				result = finder.findColor(data, bgr, degreeStart, degreeEnd,
						subColorBGR, direction, subColorBGR1, direction1);

			} else {
				result = finder.findColor(data, bgr, degreeStart, degreeEnd);

			}

			int[][] r = new int[result.size()][2];
			for (int i = 0; i < result.size(); i++) {
				r[i][0] = result.get(i)[0];
				r[i][1] = result.get(i)[1];
			}
			return r;
		} catch (Exception e) {
			return new int[][] { new int[] {} };
		}

	}

}
